package com.zxq.ruoyi.controller;

import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.zxq.ruoyi.channel.SynchroniseMessage;
import com.zxq.ruoyi.channel.platform.PlatformMessageServiceImpl;
import com.zxq.ruoyi.domain.*;
import com.zxq.ruoyi.domain.vo.*;
import com.zxq.ruoyi.enums.ECodeEnum;
import com.zxq.ruoyi.enums.EPlatformCmdType;
import com.zxq.ruoyi.enums.ESponsor;
import com.zxq.ruoyi.network.tcp.cache.TcpChannelCache;
import com.zxq.ruoyi.service.impl.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;

/**
 * 设备Controller
 * 
 * @author ruoyi
 * @date 2022-09-16
 */
@RestController
@RequestMapping("/device")
@Slf4j
public class IotDeviceController extends BaseController
{
    /**
     * 设备服务
     */
    @Autowired
    private IotDeviceServiceImpl iotDeviceService;

    /**
     * 产品服务
     */
    @Autowired
    private IotProductServiceImpl productService;

    /**
     * 产品服务
     */
    @Autowired
    private IotCmdServiceImpl iotCmdService;

    /**
     * 产品解释服务
     */
    @Autowired
    private IotCmdExplainServiceImpl iotCmdExplainService;

    /**
     * 项目服务
     */
    @Autowired
    private IotProjectServiceImpl projectService;

    /**
     * 帧服务
     */
    @Autowired
    private IotFrameServiceImpl iotFrameService;

    /**
     * 平台消息服务
     */
    @Autowired
    private PlatformMessageServiceImpl platformMessageService;

    /**
     * 同步消息队列
     */
    @Autowired
    private SynchroniseMessage synchroniseMessage;


    /**
     * 查询设备列表
     */
    @RequiresPermissions("iot:device:list")
    @GetMapping("/list")
    public DeviceVoInfo list(IotDevice iotDevice) {
        startPage();
        List<IotDevice> list = iotDeviceService.selectIotDeviceList(iotDevice);

        DeviceVoInfo rspData = new DeviceVoInfo();
        rspData.setCode(200);
        rspData.setRows(list);
        rspData.setProductList(productService.selectIotProductList(new IotProduct()));
        rspData.setFrameList(iotFrameService.selectIotFrameList(new IotFrame()));
        rspData.setProjectList(projectService.selectIotProjectList(new IotProject()));

        rspData.setMsg("查询成功");
        rspData.setTotal((new PageInfo(list)).getTotal());

        return rspData;
    }

    /**
     * 导出设备列表
     */
    @RequiresPermissions("iot:device:export")
    @Log(title = "设备", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, IotDevice iotDevice) {
        List<IotDevice> list = iotDeviceService.selectIotDeviceList(iotDevice);
        ExcelUtil<IotDevice> util = new ExcelUtil<IotDevice>(IotDevice.class);
        util.exportExcel(response, list, "设备数据");
    }

    /**
     * 获取设备详细信息
     */
    @RequiresPermissions("iot:device:query")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return AjaxResult.success(iotDeviceService.selectIotDeviceById(id));
    }


    /**
     * 获取设备详细信息
     */
    @GetMapping(value = "/cmd/explain/{id}")
    public AjaxResult getCmdExplainId(@PathVariable("id") Long id) {
        IotDevice iotDevice = iotDeviceService.selectIotDeviceById(id);
        Long packetId = productService.selectIotProductById(iotDevice.getProductId()).getPacketId();

        IotCmd iotCmd = new IotCmd();
        iotCmd.setPacketId(packetId);
        Long sponsor = Long.valueOf(ESponsor.platform.getValue());
        iotCmd.setSponsor(sponsor);
        iotCmd.setPacketId(packetId);
        iotCmd.setCmdType(EPlatformCmdType.CMD.getValue().longValue());

        List<IotCmd>  cmdList = iotCmdService.selectIotCmdList(iotCmd);
        iotCmd.setCmdType(EPlatformCmdType.NOTICE.getValue().longValue());
        List<IotCmd>  noticeList = iotCmdService.selectIotCmdList(iotCmd);
        cmdList.addAll(noticeList);



        DevCmdExplainVo devCmdExplainVo = new DevCmdExplainVo();

        devCmdExplainVo.setDevId(iotDevice.getDevId());
        List<CmdExplainVo> cmdExplainVos = new ArrayList<>();
        if(cmdList.size() == 0) {
            CmdExplainVo cmdExplainVo = new CmdExplainVo();
            cmdExplainVo.setCmdId(-1L);
            cmdExplainVo.setCmdName("请先配置数据包和指令");
            JSONObject json = new JSONObject();
            json.put("error","please config packet");
            cmdExplainVo.setCmdJson(json);
            cmdExplainVos.add(cmdExplainVo);
            devCmdExplainVo.setCmdExplainVos(cmdExplainVos);
        }
        for(IotCmd item: cmdList) {
            IotCmdExplain iotCmdExplain = new IotCmdExplain();
            iotCmdExplain.setCmdId(item.getId());
            List<IotCmdExplain> cmdExplains = iotCmdExplainService.selectIotCmdExplainList(iotCmdExplain);
            CmdExplainVo cmdExplainVo = new CmdExplainVo();
            if(cmdExplains.size() == 0) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("tip","no config any packetFiled!");
                cmdExplainVo.setCmdJson(jsonObject);
            } else {
               String json =  cmdExplains.get(0).getJson();
               cmdExplainVo.setCmdId(item.getId());
               cmdExplainVo.setCmdName(item.getRemark());
               cmdExplainVo.setCmdJson(JSON.parseObject(json));
            }
           cmdExplainVos.add(cmdExplainVo);
        }

        devCmdExplainVo.setCmdExplainVos(cmdExplainVos);

        System.out.println(JSON.toJSONString(devCmdExplainVo));

        return AjaxResult.success(devCmdExplainVo);
    }

    /**
     * 设备指令操作
     */
    @PostMapping(value = "/cmd/operate")
    public AjaxResult operateCmd(@RequestBody DevCmdVo devCmdVo) {
        log.info("cmd operation:" + JSON.toJSONString(devCmdVo));
        UserOperateVO userOperateVO = new UserOperateVO();
        checkDevice(devCmdVo, userOperateVO);
        if(!userOperateVO.getSuccess()) {
            return AjaxResult.success(userOperateVO);
        }
        IotCmd iotCmdDo = iotCmdService.selectIotCmdById(devCmdVo.getCmdId());
        if(iotCmdDo == null) {
            log.info("not find this cmd!");
            userOperateVO.setCode(ECodeEnum.NotFindCmd.getCode());
            userOperateVO.setMessage(ECodeEnum.NotFindCmd.getMsg());
            userOperateVO.setSuccess(false);
            return AjaxResult.success(userOperateVO);
        }
        if(TcpChannelCache.getChannel(devCmdVo.getDevId()) == null) {
            log.info(String.format("device:%s offline",devCmdVo.getDevId()));
            userOperateVO.setSuccess(false);
            userOperateVO.setCode(ECodeEnum.DeviceOffline.getCode());
            userOperateVO.setMessage(ECodeEnum.DeviceOffline.getMsg());
            return AjaxResult.success(userOperateVO);
        }

        EPlatformCmdType platformCmdType = EPlatformCmdType.getType(iotCmdDo.getCmdType().intValue());
        log.info(String.format("device:%s cmdType:%s",devCmdVo.getDevId(),platformCmdType.toString()));
        if(platformCmdType == EPlatformCmdType.CMD) {
            DevCmdVo resultDTO = platformMessageService.platformCmd(devCmdVo);
            if (resultDTO != null) {
                userOperateVO.setData(resultDTO);
                userOperateVO.setCode(ECodeEnum.Success.getCode());
                userOperateVO.setMessage(ECodeEnum.Success.getMsg());
                userOperateVO.setSuccess(true);
            }
        }
        if(platformCmdType == EPlatformCmdType.NOTICE ) {
            platformMessageService.platformNotify(devCmdVo);
            userOperateVO.setCode(ECodeEnum.Success.getCode());
            userOperateVO.setMessage(ECodeEnum.Success.getMsg());
            userOperateVO.setSuccess(true);
        }

        if(platformCmdType == EPlatformCmdType.RESULT ) {
            synchroniseMessage.notifyPlatformMessage(devCmdVo.getDevId()
                    ,devCmdVo.getCmdId(),devCmdVo);
            userOperateVO.setCode(ECodeEnum.Success.getCode());
            userOperateVO.setMessage(ECodeEnum.Success.getMsg());
            userOperateVO.setSuccess(true);
        }
        //如果回复容器里面没有对应的key，则是通知
        if(platformCmdType == EPlatformCmdType.NOTICE_OR_RESULT) {
            Boolean rst = synchroniseMessage.notifyPlatformMessage(devCmdVo.getDevId()
                    ,iotCmdDo.getResultId(),devCmdVo);
            if(!rst) {
                platformMessageService.platformNotify(devCmdVo);
            }
            userOperateVO.setCode(ECodeEnum.Success.getCode());
            userOperateVO.setMessage(ECodeEnum.Success.getMsg());
            userOperateVO.setSuccess(true);
        }

        return AjaxResult.success(userOperateVO);
    }



    /**
     * 检查设备是否符合规范
     * @param devCmdVo 平台指令数据
     * @param operateVO 返回的数据格式
     */
    private void checkDevice(DevCmdVo devCmdVo, UserOperateVO operateVO) {
        operateVO.setSuccess(true);
        String devId =  devCmdVo.getDevId();
        IotDevice iotDeviceCondition = new IotDevice();
        iotDeviceCondition.setDevId(devId);
        List<IotDevice> iotDeviceDos = iotDeviceService.selectIotDeviceList(iotDeviceCondition);
        if(iotDeviceDos.size() == 0) {
            operateVO.setMessage(ECodeEnum.IllegalDevice.getMsg());
            operateVO.setCode(ECodeEnum.IllegalDevice.getCode());
            operateVO.setSuccess(false);
            System.out.println(String.format("devId:%s not found!",devId));
            return;
        }
        IotDevice iotDeviceDo = iotDeviceDos.get(0);
        Long projectId = iotDeviceDo.getProjectId();
        if(projectId == null || projectService.selectIotProjectById(projectId) == null) {
            operateVO.setMessage(ECodeEnum.NotFindProduct.getMsg());
            operateVO.setCode(ECodeEnum.NotFindProduct.getCode());
            operateVO.setSuccess(false);
            System.out.println(String.format("devId:{0} not belong any product!",projectId));
        }

    }


    /**
     * 新增设备
     */
    @RequiresPermissions("iot:device:add")
    @Log(title = "设备", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody IotDevice iotDevice) {
        return toAjax(iotDeviceService.insertIotDevice(iotDevice));
    }

    /**
     * 修改设备
     */
    @RequiresPermissions("iot:device:edit")
    @Log(title = "设备", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody IotDevice iotDevice) {
        return toAjax(iotDeviceService.updateIotDevice(iotDevice));
    }

    /**
     * 删除设备
     */
    @RequiresPermissions("iot:device:remove")
    @Log(title = "设备", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(iotDeviceService.deleteIotDeviceByIds(ids));
    }
}
